package com.acegear.horizon.utils;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.json.JacksonJsonParser;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

/**
 * Created by wangsike on 16/9/13.
 */
@Service
public class JwtTokenUtil implements Serializable {

    static final String CLAIM_KEY_USERNAME = "sub";
    static final String CLAIM_KEY_ROLE = "role";
    static final String CLAIM_KEY_TOKEN = "iss";
    private static final long serialVersionUID = -3301605591108950415L;
    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private Long expiration;


    public Claims getClaimsFromToken(String token) {
        String body = token.split(Pattern.quote("."))[1];
        String decodedBody = new String(Base64Utils.decode(body.getBytes()));
        Map<String, Object> map = new JacksonJsonParser().parseMap(decodedBody);
        String iss = (String) map.get("iss");
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey((secret + iss).getBytes())
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }

    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }

    public String generateToken(String userId, String accessToken, String role) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME, userId);
        claims.put(CLAIM_KEY_ROLE, role);
        claims.put(CLAIM_KEY_TOKEN, accessToken);
        return generateToken(claims);
    }

    private String generateToken(Map<String, Object> claims) {
        String accessToken = (String) claims.get(CLAIM_KEY_TOKEN);
        return Jwts.builder()
                .setHeader((Map<String, Object>) Jwts.header().setType(Header.JWT_TYPE))
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS256, (secret + accessToken).getBytes())
                .compact();
    }
}